/* vccd/monitor.c 
 * 
 * This file is part of vccd. 
 * 
 * vccd is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * vccd is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with vccd. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/times.h>

#include <config.h>
#include <vcc/vccd.h>


int allocated, current;
extern int nusers, system_fd;

#if CONFIG_ADVANCED_AMALLOC

struct klist_node amalloc_log = KLIST_NODE_INIT(&amalloc_log);

#endif


void *__amalloc(int nbytes, const char *fn) {
	void *p;

	current += nbytes;
	allocated += nbytes;

	if (unlikely(!(p = malloc(nbytes)))) {
		vcc_log("*** malloc() failed\n");
		amalloc_report(NULL);

		return NULL;
	}

#if CONFIG_ADVANCED_AMALLOC
	struct klist_node *n;

	if (unlikely(!(n = malloc(sizeof(struct klist_node))))) {
		vcc_log("*** malloc() failed. \n");

		return NULL;
	}

	klist_init(n);

	n->data = (char *) fn;
	n->sending = (void *) p;
	n->value = nbytes;

	klist_add(&amalloc_log, n);
#else
	(void) fn;
#endif

	return p;
}


int afree(void *p, int nbytes) {
	current -= nbytes;
	free(p);

#if CONFIG_ADVANCED_AMALLOC
	struct klist_node *n;

	for (n = amalloc_log.next; n != &amalloc_log; n = n->next) 
		if (n->sending == p) 
			break;

	if (unlikely(n == &amalloc_log)) {
		vcc_log("*** broken amalloc_log. \n");

		return 1;
	}

	klist_del(&amalloc_log, n);
	free(n);

#endif
	return 0;
}


int amalloc_report(char *s) {
	(void) s;

	printf("amalloc report: \n");

	printf("\tallocated\tused\n");
	printf("\t%d\t\t%d\n", allocated, current);
	printf("\t%d KB\t\t%d KB\n", allocated >> 10, current >> 10);

#if CONFIG_ADVANCED_AMALLOC
	struct klist_node *n;

	printf("\nadvanced amalloc report: \n");

	for (n = amalloc_log.next; n != &amalloc_log; n = n->next) 
		printf("\t%s: %ld bytes  %ld KB\n", (char *) n->data, n->value, (n->value >> 10));
#endif

	printf("\ntotal: %d users online. \n", nusers);

	return 0;
}


int monitor_info(int fd, struct vcc_request *req) {
	char msg[128];

	if (fd != system_fd) {
		relay_send_msg(fd, "sysinfo: only root can do that. ", "system");
		vcc_log("%d:%s tried to get sysinfo. \n", fd, req->usrname);
		vcc_info("WSYSINFO %s %d\n", req->usrname, fd);

		return 1;
	}

	sprintf(msg, "\namalloc info: \n%d (%d KB) allocated, %d (%d KB) using\n", allocated, allocated >> 10, 
			current, current >> 10);

	relay_send_msg(fd, msg, "system");
	vcc_log("sysinfo sent to %d. \n", fd);

	return 0;
}





